﻿using System;
using System.Text;
using TencentCloud.Ssl.V20191205;
using TencentCloud.Ssl.V20191205.Models;
using System.IO;
using System.Linq;

namespace txcloud.sdk.SSL
{
    using SanlieHash.Fast;
    using yacomp;
    using txcloud.sdk.Core;
    public class Certificate
    {
        public const string DvAuthMethod_FILE = "FILE";
        public const string MIME_ZIP = "application/zip";
        internal TxCred cred { get; set; }
        internal TxProfile profile { get; set; }
        ///https://console.cloud.tencent.com/api/explorer?Product=ssl&Version=2019-12-05&Action=DownloadCertificate
        public Certificate() {
            cred = TxCloudSDK.TxCred;
            profile = new TxProfile("ssl.tencentcloudapi.com");
        }
        public Certificate(TxCred cred)
        {
            this.cred = cred;
            profile = new TxProfile("ssl.tencentcloudapi.com");
        }

        public Certificates[] ReadCertificates(ulong offset = 0, ulong limit = 50)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            SslClient client = new SslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DescribeCertificatesRequest req = new DescribeCertificatesRequest();
            req.Offset = offset;
            req.Limit = limit;
            // 返回的resp是一个DescribeCertificatesResponse的实例，与请求对象对应
            DescribeCertificatesResponse resp = client.DescribeCertificatesSync(req);
            if (resp.TotalCount > 0)
            {
                return resp.Certificates;
            }
            return new Certificates[0];
        }
        public DescribeCertificateDetailResponse ReadCertificateDetail(string certId)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            SslClient client = new SslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DescribeCertificateDetailRequest req = new DescribeCertificateDetailRequest();
            req.CertificateId = certId;
            // 返回的resp是一个DescribeCertificateDetailResponse的实例，与请求对象对应
            DescribeCertificateDetailResponse resp = client.DescribeCertificateDetailSync(req);
            return resp;
        }
        /// <summary>
        /// 读取文件验证内容
        /// </summary>
        /// <param name="certId"></param>
        /// <returns></returns>
        public string ReadFileAuth(string certId)
        {
            var info = ReadCertificateDetail(certId);
            if (info.VerifyType != Certificate.DvAuthMethod_FILE) return string.Empty;
            return info.DvAuthDetail.DvAuthValue;
        }

        /// <summary>
        /// 下载证书到指定路径
        /// </summary>
        /// <param name="certId"></param>
        /// <param name="path"></param>
        public Stream GetCertStream(string certId)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            SslClient client = new SslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DownloadCertificateRequest req = new DownloadCertificateRequest();
            req.CertificateId = certId;
            // 返回的resp是一个DownloadCertificateResponse的实例，与请求对象对应
            DownloadCertificateResponse resp = client.DownloadCertificateSync(req);

            if (resp.ContentType == MIME_ZIP)
            {
                return new MemoryStream(Encoding.ASCII.GetBytes(resp.Content));
            }
            return Stream.Null;
        }
        public Stream DownloadCertStream(string certId)
        {
            var stream = GetCertStream(certId);
            if (stream == Stream.Null) return stream;

            var unzip_stream = new MemoryStream();
            using (stream)
            {
                FastEncode.Base64DecodeStream(stream, unzip_stream);
            }
            return unzip_stream;
        }
        /// <summary>
        /// 下载证书到指定路径
        /// </summary>
        /// <param name="certId"></param>
        /// <param name="path"></param>
        public void DownloadCert(string certId, string path)
        {
            var stream = GetCertStream(certId);
            if (stream == Stream.Null) return;
            if (File.Exists(path)) File.Delete(path);

            using (stream)
            using (var m2 = File.Create(path))
            {
                FastEncode.Base64DecodeStream(stream, m2);
            }
        }
        public void DownloadCert(string certId, string certPath, string domain_name)
        {
            if (!Directory.Exists(certPath)) Directory.CreateDirectory(certPath);
            using (var certsr = DownloadCertStream(certId)) if (certsr != null) Unzip(certsr, certPath, domain_name.Trim());
        }

        internal static void Unzip(Stream zip, string path, string domain_name)
        {
            // 只取 xxx.key   xxx.pem   xxx.csr   xxx.pfx
            domain_name = domain_name.ToLower().TrimEnd('.');
            var get_filenames = new string[8];
            get_filenames[0] = $"{domain_name}.key";
            get_filenames[1] = $"{domain_name}.pem";
            get_filenames[2] = $"{domain_name}.csr";
            get_filenames[3] = $"{domain_name}.pfx";
            if (domain_name.StartsWith("www.")) for (var i = 4; i < 8; i++) get_filenames[i] = get_filenames[i - 4].Substring(4);
            else for (var i = 4; i < 8; i++) get_filenames[i] = "www." + get_filenames[i - 4];

            zip.Seek(0, SeekOrigin.Begin);
            using (var f = new YacompZip(zip))
            {
                var disk = f.GetStorage();
                foreach (var _file in disk.LoopFiles())
                {
                    if (!get_filenames.Contains(_file.FileName.ToLower())) continue;

                    var _path = Path.Combine(path, $"{domain_name}.{_file.FileExtension}");
                    if (File.Exists(_path)) File.Delete(_path);
                    _file.ToStream(File.Create(_path));
                }
            }
        }
        public string ApplyCert(string domain)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            SslClient client = new SslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            ApplyCertificateRequest req = new ApplyCertificateRequest();
            req.DvAuthMethod = DvAuthMethod_FILE;
            req.DomainName = domain;
            // 返回的resp是一个ApplyCertificateResponse的实例，与请求对象对应
            ApplyCertificateResponse resp = client.ApplyCertificateSync(req);
            return resp.CertificateId;
        }
        /// !单域名
        public bool CheckDomainVerification(string certId)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            SslClient client = new SslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            CheckCertificateDomainVerificationRequest req = new CheckCertificateDomainVerificationRequest();
            req.CertificateId = certId;
            // 返回的resp是一个CheckCertificateDomainVerificationResponse的实例，与请求对象对应
            CheckCertificateDomainVerificationResponse resp = client.CheckCertificateDomainVerificationSync(req);
            if (resp.VerificationResults.Length == 0) return false;
            return resp.VerificationResults[0].CaCheck == 2;
        }

        /// !单域名
        public bool CheckDomainLocalVerification(string certId)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            SslClient client = new SslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            CheckCertificateDomainVerificationRequest req = new CheckCertificateDomainVerificationRequest();
            req.CertificateId = certId;
            // 返回的resp是一个CheckCertificateDomainVerificationResponse的实例，与请求对象对应
            CheckCertificateDomainVerificationResponse resp = client.CheckCertificateDomainVerificationSync(req);
            if (resp.VerificationResults.Length == 0) return false;
            return resp.VerificationResults[0].LocalCheck == 1;
        }
        public void ApplyCertVerification(string certId)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            SslClient client = new SslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            CompleteCertificateRequest req = new CompleteCertificateRequest();
            req.CertificateId = certId;
            // 返回的resp是一个CompleteCertificateResponse的实例，与请求对象对应
            client.CompleteCertificateSync(req);
        }
        /// <summary>
        /// 切换为 文件验证
        /// </summary>
        /// <param name="certId"></param>
        public void ToFileCertVerification(string certId)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            ExtSslClient client = new ExtSslClient(cred.Get(), "", profile.Get());
            ModifyDomainAuthMethodRequest req = new ModifyDomainAuthMethodRequest();
            req.CertificateId = certId;
            req.DvAuthMethod = DvAuthMethod_FILE;
            // 返回的resp是一个ReplaceCertificateResponse的实例，与请求对象对应
            client.ModifyDomainAuthMethodSync(req);
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="certId"></param>
        /// <returns></returns>
        public bool DeleteCertificate(string certId)
        {
            // 实例化要请求产品的client对象,clientProfile是可选的
            ExtSslClient client = new ExtSslClient(cred.Get(), "", profile.Get());
            // 实例化一个请求对象,每个接口都会对应一个request对象
            DeleteCertificateRequest req = new DeleteCertificateRequest();
            req.CertificateId = certId;
            // 返回的resp是一个DeleteCertificateResponse的实例，与请求对象对应
            DeleteCertificateResponse resp = client.DeleteCertificateSync(req);
            return resp.DeleteResult??false;
        }
    }
}
